/*
 * @(#)MethodBuilder.java 1.8 03/12/19
 * 
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. SUN
 * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.sun.tools.doclets.internal.toolkit.builders;

import com.sun.tools.doclets.internal.toolkit.util.*;
import com.sun.tools.doclets.internal.toolkit.*;
import com.sun.javadoc.*;
import java.util.*;
import java.lang.reflect.*;

/**
 * Builds documentation for a method.
 * 
 * This code is not part of an API. It is implementation that is subject to
 * change. Do not use it as an API
 * 
 * @author Jamie Ho
 * @since 1.5
 */
public class MethodBuilder extends AbstractMemberBuilder {
	
	/**
	 * The index of the current field that is being documented at this point in
	 * time.
	 */
	private int currentMethodIndex;
	
	/**
	 * The class whose methods are being documented.
	 */
	private ClassDoc classDoc;
	
	/**
	 * The visible methods for the given class.
	 */
	private VisibleMemberMap visibleMemberMap;
	
	/**
	 * The writer to output the method documentation.
	 */
	private MethodWriter writer;
	
	/**
	 * The methods being documented.
	 */
	private List methods;
	
	private MethodBuilder(Configuration configuration) {
		super(configuration);
	}
	
	/**
	 * Construct a new MethodBuilder.
	 * 
	 * @param configuration the current configuration of the doclet.
	 * @param classDoc the class whoses members are being documented.
	 * @param writer the doclet specific writer.
	 * 
	 * @return an instance of a MethodBuilder.
	 */
	public static MethodBuilder getInstance(Configuration configuration,
			ClassDoc classDoc, MethodWriter writer) {
		MethodBuilder builder = new MethodBuilder(configuration);
		builder.classDoc = classDoc;
		builder.writer = writer;
		builder.visibleMemberMap = new VisibleMemberMap(classDoc,
				VisibleMemberMap.METHODS, configuration.nodeprecated);
		builder.methods = new ArrayList(
				builder.visibleMemberMap.getLeafClassMembers(configuration));
		if (configuration.getMemberComparator() != null) {
			Collections.sort(builder.methods,
					configuration.getMemberComparator());
		}
		return builder;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public String getName() {
		return "MethodDetails";
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void invokeMethod(String methodName, Class[] paramClasses,
			Object[] params) throws Exception {
		if (DEBUG) {
			configuration.root.printError("DEBUG: " + this.getClass().getName()
					+ "." + methodName);
		}
		Method method = this.getClass().getMethod(methodName, paramClasses);
		method.invoke(this, params);
	}
	
	/**
	 * Returns a list of methods that will be documented for the given class.
	 * This information can be used for doclet specific documentation
	 * generation.
	 * 
	 * @param classDoc the {@link ClassDoc} we want to check.
	 * @return a list of methods that will be documented.
	 */
	public List members(ClassDoc classDoc) {
		return visibleMemberMap.getMembersFor(classDoc);
	}
	
	/**
	 * Returns the visible member map for the methods of this class.
	 * 
	 * @return the visible member map for the methods of this class.
	 */
	public VisibleMemberMap getVisibleMemberMap() {
		return visibleMemberMap;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public boolean hasMembersToDocument() {
		return methods.size() > 0;
	}
	
	/**
	 * Build the method documentation.
	 */
	public void buildMethodDoc(List elements) {
		if (writer == null) {
			return;
		}
		for (currentMethodIndex = 0; currentMethodIndex < methods.size(); currentMethodIndex++) {
			build(elements);
		}
	}
	
	/**
	 * Build the overall header.
	 */
	public void buildHeader() {
		writer.writeHeader(classDoc,
				configuration.getText("doclet.Method_Detail"));
	}
	
	/**
	 * Build the header for the individual method.
	 */
	public void buildMethodHeader() {
		writer.writeMethodHeader((MethodDoc) methods.get(currentMethodIndex),
				currentMethodIndex == 0);
	}
	
	/**
	 * Build the signature.
	 */
	public void buildSignature() {
		writer.writeSignature((MethodDoc) methods.get(currentMethodIndex));
	}
	
	/**
	 * Build the deprecation information.
	 */
	public void buildDeprecationInfo() {
		writer.writeDeprecated((MethodDoc) methods.get(currentMethodIndex));
	}
	
	/**
	 * Build the comments for the method. Do nothing if
	 * {@link Configuration#nocomment} is set to true. If this method
	 */
	public void buildMethodComments() {
		if (!configuration.nocomment) {
			MethodDoc method = (MethodDoc) methods.get(currentMethodIndex);
			
			if (method.inlineTags().length == 0) {
				DocFinder.Output docs = DocFinder.search(new DocFinder.Input(
						method));
				method = docs.inlineTags != null && docs.inlineTags.length > 0
						? (MethodDoc) docs.holder
						: method;
				
			}
			// NOTE: When we fix the bug where ClassDoc.interfaceTypes() does
			// not pass all implemented interfaces, holder will be the
			// interface type. For now, it is really the erasure.
			writer.writeComments(method.containingClass(), method);
		}
	}
	
	/**
	 * Build the tag information.
	 */
	public void buildTagInfo() {
		writer.writeTags((MethodDoc) methods.get(currentMethodIndex));
	}
	
	/**
	 * Build the footer of the method.
	 */
	public void buildMethodFooter() {
		writer.writeMethodFooter();
	}
	
	/**
	 * Build the overall footer.
	 */
	public void buildFooter() {
		writer.writeFooter(classDoc);
	}
	
	/**
	 * Return the method writer for this builder.
	 * 
	 * @return the method writer for this builder.
	 */
	public MethodWriter getWriter() {
		return writer;
	}
}
